package com.thy.service.impl;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hospital.common.base.PageResult;
import com.hospital.common.base.Result;
import com.hospital.common.base.ThreadAttributes;
import com.hospital.common.dto.management.module.BackendDoctorInfoDto;
import com.hospital.common.dto.management.module.DoctorQueryDto;
import com.hospital.common.dto.management.module.RegisterDto;
import com.hospital.common.enums.ResultStatus;
import com.hospital.common.enums.RoleType;
import com.hospital.common.exception.GlobalException;
import com.hospital.common.pojo.TDoctorInfo;
import com.hospital.common.pojo.TUser;
import com.hospital.common.utils.PwdUtils;
import com.hospital.common.utils.ThreadLocalUtils;
import com.hospital.common.vo.management.module.DoctorInfoVo;
import com.thy.feign.DataSimulationFeign;
import com.thy.mapper.TDoctorInfoMapper;
import com.thy.mapper.TUserMapper;
import com.thy.service.TDoctorInfoService;
import com.thy.utils.MinioUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

/**
 * <p>
 * 医生信息 服务实现类
 * </p>
 *
 * @author author
 * @since 2025-09-12
 */
@Service
public class TDoctorInfoServiceImpl extends ServiceImpl<TDoctorInfoMapper, TDoctorInfo> implements TDoctorInfoService {
    @Autowired
    private TDoctorInfoMapper tDoctorInfoMapper;
    @Autowired
    private TUserMapper tUserMapper;
    @Autowired
    private DataSimulationFeign dataSimulationFeign;
    @Autowired
    private MinioUtils minioUtils;

    @Override
    public List<DoctorInfoVo> getAllDoctor() {
        return tDoctorInfoMapper.getAllDoctor().stream().peek(this::setMinioPath).toList();
    }

    @Override
    public PageResult<DoctorInfoVo> getDoctorByDepartmentAndName(Long departmentId, String name,Long pageNum,Long pageSize) {
        Page<DoctorInfoVo> page = new Page<>(pageNum,pageSize);
        IPage<DoctorInfoVo> doctorInfoVos = tDoctorInfoMapper.getDoctorByDepartmentAndName(departmentId,name,page);
        if(doctorInfoVos != null){
            return new PageResult<>(doctorInfoVos.getTotal(),doctorInfoVos.getRecords().stream().peek(this::setMinioPath).toList());
        }else {
            return new PageResult<>(0L,new ArrayList<>());
        }

    }

    @Override
    public DoctorInfoVo getDoctor(Long userId) {
        DoctorInfoVo doctor = tDoctorInfoMapper.getDoctor(userId);
        doctor.setMinioPath(minioUtils.getPresignedUrl(doctor.getPhotoDirPath() + "/" + doctor.getPhotoFile()));
        return doctor;
    }

    @Override
    public void addDoctor(TUser user, TDoctorInfo doctorInfo) {
        String pwd = null;
        try {
            pwd = PwdUtils.sha256(user.getPassword());
        } catch (Exception e) {
            throw new GlobalException(4001,"密码加密失败");
        }
        user.setPassword(pwd);
        Result<Long> userResult = dataSimulationFeign.addUser(user);
        Result<Long> doctorInfoResult = dataSimulationFeign.addDoctorInfo(doctorInfo);
        if (userResult.getCode() == 0){
            throw new GlobalException(1001,"添加失败");
        }
        if (doctorInfoResult.getCode() == 0){
            throw new GlobalException(1002,"医生信息添加失败");
        }
    }

    @Override
    public void updateDoctor(TDoctorInfo doctorInfo, Long userId) {
        Long infoId = tDoctorInfoMapper.getInfoIdByUserId(userId);
        doctorInfo.setId(infoId);
        Result<?> result = dataSimulationFeign.updateDoctorInfo(doctorInfo);
        if (result.getCode() == 0){
            throw new GlobalException(2001,"修改失败");
        }
    }

    @Override
    @Transactional
    public void deleteDoctor(Long userId) {
        verify();
        TUser user = checkDoctor(userId);
        Result<?> result = dataSimulationFeign.deleteUser(userId);
        dataSimulationFeign.deleteDoctorInfo(user.getInfoId());
        if (result.getCode() == 0){
            throw new GlobalException(3001,"删除失败");
        }
    }

    @Override
    public String  updateImg(MultipartFile file) {
        String photoDirPath = "doctor";
        String photoFile = UUID.randomUUID().toString().replace("-", "");
        ThreadAttributes threadAttributes = ThreadLocalUtils.get();
        Long userId = threadAttributes.getUserId();
        tDoctorInfoMapper.addImgPath(userId,photoDirPath,photoFile);
        String objectName = photoDirPath+"/"+photoFile;
        try {
            return minioUtils.uploadFile(objectName, file.getInputStream(), file.getSize(), file.getContentType());
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public List<DoctorInfoVo> getDoctorLimit(Integer num) {
        LambdaQueryWrapper<TDoctorInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.last("limit "+num);
        return tDoctorInfoMapper.selectList(queryWrapper).stream().map(this::convert).toList();
    }

    @Override
    public PageResult<DoctorInfoVo> getDoctorInPage(Integer pageNum, Integer pageSize) {
        LambdaQueryWrapper<TDoctorInfo> queryWrapper = new LambdaQueryWrapper<>();
        Page<TDoctorInfo> page = page(new Page<>(pageNum,pageSize),queryWrapper);
        return new PageResult<>(page.getTotal(),page.getRecords().stream().map(this::convert).toList());
    }

    @Override
    public List<DoctorInfoVo> getDoctorByDepartment(Long departmentId) {
        LambdaQueryWrapper<TDoctorInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TDoctorInfo::getDepartmentId,departmentId);
        return tDoctorInfoMapper.selectList(queryWrapper).stream().map(this::convert).toList();
    }

    @Override
    public PageResult<DoctorInfoVo> getDoctorInPageByDepartment(DoctorQueryDto doctorQueryDto) {
        LambdaQueryWrapper<TDoctorInfo> queryWrapper = new LambdaQueryWrapper<>();
        if(!ObjectUtils.isEmpty(doctorQueryDto.getDepartmentId())){
            queryWrapper.eq(TDoctorInfo::getDepartmentId,doctorQueryDto.getDepartmentId());
        }
        Page<TDoctorInfo> page = page(new Page<>(doctorQueryDto.getPageNum(),doctorQueryDto.getPageSize()),queryWrapper);
        return new PageResult<>(page.getTotal(),page.getRecords().stream().map(this::convert).toList());
    }

    @Override
    public void adminUpdateDoctorInfo(BackendDoctorInfoDto backendDoctorInfoDto) {
        verify();
        TUser user = checkDoctor(backendDoctorInfoDto.getDoctorId());
        user.setPhone(backendDoctorInfoDto.getPhone());
        TDoctorInfo doctorInfo = new TDoctorInfo();
        BeanUtils.copyProperties(backendDoctorInfoDto,doctorInfo);
        doctorInfo.setUpdateTime(LocalDateTime.now());
        Result<?> updateUser = dataSimulationFeign.updateUser(user);
        Result<?> updateDoctorInfo = dataSimulationFeign.updateDoctorInfo(doctorInfo);
        if(!updateUser.getCode().equals(ResultStatus.SUCCESS.getCode())&&!updateDoctorInfo.getCode().equals(ResultStatus.SUCCESS.getCode())){
            throw new GlobalException(4004,"更新失败");
        }
    }

    @Override
    public void register(RegisterDto registerDto) {
        checkAlreadyExist(registerDto.getAccount());
        TUser user = new TUser();
        BeanUtils.copyProperties(registerDto,user);
        try {
            user.setPassword(PwdUtils.sha256(registerDto.getPassword()));
            user.setName(registerDto.getName());
            user.setAccount(registerDto.getAccount());
            user.setRole(RoleType.DOCTOR.value);
            user.setSex(registerDto.getSex());
            user.setPhone(registerDto.getPhone());
            user.setCreateTime(LocalDateTime.now());
        } catch (NoSuchAlgorithmException e) {
            throw new GlobalException(4001,"密码加密失败");
        }
        TDoctorInfo doctorInfo = new TDoctorInfo();
        BeanUtils.copyProperties(registerDto,doctorInfo);
        doctorInfo.setCreateTime(LocalDateTime.now());
        Result<Long> doctorInfoResult = dataSimulationFeign.addDoctorInfo(doctorInfo);
        if(!doctorInfoResult.getCode().equals(ResultStatus.SUCCESS.getCode())){
            throw new GlobalException(4003,"医生信息添加失败");
        }
        user.setInfoId(doctorInfoResult.getData());
        Result<Long> userResult = dataSimulationFeign.addUser(user);
        if(!userResult.getCode().equals(ResultStatus.SUCCESS.getCode())&&!doctorInfoResult.getCode().equals(ResultStatus.SUCCESS.getCode())){
            throw new GlobalException(4004,"注册失败");
        }
    }
    private void checkAlreadyExist(String account){
        LambdaQueryWrapper<TUser> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TUser::getAccount, account);
        if(tUserMapper.selectOne(queryWrapper) != null){
            throw new GlobalException(4002,"用户已存在");
        }
    }
    private void verify(){
        ThreadAttributes ta = ThreadLocalUtils.get();
        if(ObjectUtils.isEmpty( ta)){
            throw new GlobalException(4001,"管理员不存在");
        }
        if(!ta.getRoleType().equals(RoleType.ADMIN.value)){
            throw new GlobalException(4002,"权限不足");
        }
    }
    private TUser checkDoctor(Long doctorId){
        LambdaQueryWrapper<TUser> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TUser::getId,doctorId)
                .eq(TUser::getRole, RoleType.DOCTOR.value);
        TUser user = tUserMapper.selectOne(queryWrapper);
        if(ObjectUtils.isEmpty(user)){
            throw new GlobalException(4003,"医生不存在");
        }
        return user;
    }

    private DoctorInfoVo convert(TDoctorInfo doctorInfo){
        DoctorInfoVo doctorInfoVo = new DoctorInfoVo();
        LambdaQueryWrapper<TUser> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TUser::getInfoId,doctorInfo.getId())
                .eq(TUser::getRole, RoleType.DOCTOR.value);
        BeanUtils.copyProperties(doctorInfo, doctorInfoVo);
        TUser user = tUserMapper.selectOne(queryWrapper);
        if(!ObjectUtils.isEmpty(user)){
            doctorInfoVo.setDoctorId(user.getId());
            doctorInfoVo.setMinioPath(minioUtils.getPresignedUrl(doctorInfo.getPhotoDirPath() + "/" + doctorInfo.getPhotoFile()));
            doctorInfoVo.setName(user.getName());
            doctorInfoVo.setPhone(user.getPhone());
            doctorInfoVo.setSex(String.valueOf(user.getSex()));
            doctorInfoVo.setAccount(user.getAccount());
        }
        return doctorInfoVo;
    }
    private void setMinioPath(DoctorInfoVo doctorInfoVo){
        doctorInfoVo.setMinioPath(minioUtils.getPresignedUrl(doctorInfoVo.getPhotoDirPath() + "/" + doctorInfoVo.getPhotoFile()));
    }
}
